package top.zhangjianyong.tools.timer;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import top.zhangjianyong.tools.annotation.DoTimer;
import top.zhangjianyong.tools.constant.CanteenAccount;
import top.zhangjianyong.tools.entity.Vegetable;
import top.zhangjianyong.tools.model.MealConfig;
import top.zhangjianyong.tools.service.mybatis.IVegetableService;
import top.zhangjianyong.tools.utils.*;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author ： zhangjianyong
 * @date ： 2022/9/23 3:47 PM
 */
@Slf4j
@Component
@Deprecated
public class CanteenTimer {

    @Value("${canteen.url}")
    private String startUrl;
    @Value("${canteen.timeout}")
    private Integer timeout;
    @Value("${timer-flag}")
    private Boolean timerFlag;
    /**
     * 总共点餐天数大于等于多少天表示点餐任务完成
     */
    @Value("${canteen.days}")
    private Integer days;
    /**
     * 一天的餐大于多少个表示当天的餐已全部放出
     */
    @Value("${canteen.menus}")
    private Integer menus;

    private Set<String> orderedUrl = new HashSet<>();
    @Autowired
    private IVegetableService iVegetableService;

    private final static String EMAIL = "605600162@qq.com";

    private final static ThreadPoolExecutor executor = new ThreadPoolExecutor(
            2, 4, 1, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(10));

    @Async
    public void orderAsync() {
        order();
    }

    //@Scheduled(cron = "0 20 17 ? * 2,3,4")//1=周日
    @DoTimer
    public void order() {
        //初始化点餐配置
        CanteenAccount.resetAll();
        //初始化菜单缓存
        CanteenVegetableHolder.init();
        try {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime endTime = now.plusMinutes(timeout);
            int dayOfWeek = now.getDayOfWeek().getValue();
            CanteenAccount account = CanteenAccount.getOneByDayOfWeek(dayOfWeek);
            if (account == null) {
                log.info("当天没有需要点餐账号");
                return;
            }
            //检查是否可以点餐
            Boolean check = doCheck(account.userName, account.password, endTime);
            if (check) {
                //取出全部需要点餐配置
                List<CanteenAccount> allAccount = CanteenAccount.getAllByDayOfWeek(dayOfWeek);

                List<Future<Integer>> collect = allAccount.stream().map(o -> {
                    OrderCallable call1 = new OrderCallable(o, EMAIL);
                    return executor.submit(call1);
                }).collect(Collectors.toList());

                //检查已点餐数据小于配置数，重新进入点餐
                if (collect.stream().map(o -> {
                    try {
                        log.info("[开放餐数] {}", o.get());
                        return o.get();
                    } catch (InterruptedException e) {
                        log.error(e.getMessage(),e);
                        return 0;
                    } catch (ExecutionException e) {
                        log.error(e.getMessage(),e);
                        return 0;
                    }

                }).anyMatch(o -> o < days)) {
                    log.info("[点餐未完成] 重新进入点餐");
                    order();
                }

                log.info("[点餐线程] 结束");
                MailUtil.send(EMAIL, "点餐结束",
                        "");
            } else {

                MailUtil.send(EMAIL, "检查点餐超时",
                        CanteenApiUtil.getMessage());

            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            try {
                MailUtil.send(EMAIL,
                        "点餐异常", ExceptionUtil.getExceptionToString(e));
                order();
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
        }

        //任务结束开始保存菜单
        List<Vegetable> list = CanteenVegetableHolder.getList();
        list.stream().forEach(v -> {
            String no = v.getNo();
            String date = v.getEatDate();
            Vegetable one = iVegetableService.getOneByNoAndDate(no, date);
            if (one == null) {
                iVegetableService.save(v);
            } else {
                v.setId(one.getId());
                iVegetableService.updateById(v);
            }
        });

    }


    /**
     * 线程处理类
     */
    public class OrderCallable implements Callable<Integer> {

        private final CanteenAccount account;
        private final String email;


        public OrderCallable(CanteenAccount account, String email) {
            this.account = account;
            this.email = email;

        }

        @Override
        public Integer call() throws Exception {
            return canteenOrder(account, email);
        }

    }

    /**
     * 点餐入口方法
     *
     * @param email
     */
    public Integer canteenOrder(CanteenAccount account, String email) {

        try {
            return doCanteenOrder(account, email);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            try {
                MailUtil.send(EMAIL,
                        "点餐异常", ExceptionUtil.getExceptionToString(e));
                canteenOrder(account, email);
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
            return 0;
        }

    }

    /**
     * 检查是否已放出餐
     *
     * @param userName 用户名
     * @param password 密码
     * @param endTime  超时时间
     * @return
     * @throws InterruptedException
     */
    public Boolean doCheck(String userName, String password, LocalDateTime endTime) throws InterruptedException {
        //获取sessionId
        String loginUrl = CanteenApiUtil.loginUrl();
        //获取des密钥
        CanteenApiUtil.loginKey(loginUrl);
        //登陆
        String indexUri = CanteenApiUtil.login(userName, password);
        //重定向首页
        CanteenApiUtil.getInfoPage(indexUri);
        //获取可点日期
        List<String> menuUris = CanteenApiUtil.getMenuUris();

        //检查是否可以点餐
        boolean flag = true;
        CanteenApiUtil.addMessage("[检查点餐] 开始检查");
        while (flag) {
            log.info("[检查] 进入放餐检查");
            for (String menuUri : menuUris) {
                List<Vegetable> menu = CanteenApiUtil.getMenu(menuUri, false);
                if (CollectionUtil.isNotEmpty(menu)
                        && menu.size() >= menus
                        && !orderedUrl.contains(menuUri)) {
                    orderedUrl.add(menuUri);
                    flag = false;
                    break;
                }
            }
            if (LocalDateTime.now().isAfter(endTime)) {
                CanteenApiUtil.addMessage("[检查超时] 当前未开放点餐");
                CanteenApiUtil.addMessage("[重新启动] 请点击链接重新启动: {}",
                        startUrl);
                return false;
            }
        }
        return true;
    }

    /**
     * 点餐流程方法
     *
     * @param email
     * @return 已经放出餐天数
     */
    public Integer doCanteenOrder(CanteenAccount account, String email) {
        log.info("[开始点餐] {}", account);
        CanteenApiUtil.addMessage("[开始点餐] ", account);
        String userName = account.userName;
        String password = account.password;
        String name = account.name();
        List<MealConfig> mealConfig = account.mealConfig;
        //获取sessionId
        String loginUrl = CanteenApiUtil.loginUrl();
        //获取des密钥
        CanteenApiUtil.loginKey(loginUrl);
        //登陆
        String indexUri = CanteenApiUtil.login(userName, password);
        //重定向首页
        CanteenApiUtil.getInfoPage(indexUri);
        //获取可点日期
        List<String> menuUris = CanteenApiUtil.getMenuUris();
        //已经放出了几天的餐
        Integer count = 0;
        //开始循环点餐
        for (String menuUri : menuUris) {
            Map<String, String> map = StringUtil.uriToMap(menuUri);
            List<Vegetable> menu = CanteenApiUtil.getMenu(menuUri, map, true);
            String cc = map.get("cc");
            //统计出餐天数
            if (menu.size() >= menus) count++;
            CanteenVegetableHolder.add(menu);
            //取出数量大于0的配置
            List<MealConfig> configs = mealConfig.stream()
                    .filter(m -> m.getTmpNum() > 0)
                    .filter(m -> m.getCc().equals(cc))
                    .collect(Collectors.toList());
            //获取餐点
            Vegetable vegetable = null;
            for (MealConfig config : configs) {
                vegetable = menu.stream()
                        .filter(config.getMeal().doFilter)
                        .findFirst().orElse(null);
                if (vegetable != null && CanteenApiUtil.addOrder(vegetable)) {
                    //点餐成功
                    config.reduce();
                    break;
                }
            }

            if (vegetable == null) {
                CanteenApiUtil.addMessage("[获取套餐] 未找到对应套餐:{}", JSONObject.toJSONString(configs));
            }

        }

        //进入购物车
        Integer carPage = CanteenApiUtil.getCarPage();
        //获取订单信息
        CanteenApiUtil.goSaveOrder();
        //提交订单
        CanteenApiUtil.saveOrder();

        //完成点餐邮件通知
        try {
            if (carPage > 0) {
                MailUtil.send(email, name + "的点餐",
                        CanteenApiUtil.getMessage());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return count;
    }


}
